﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Practices.ServiceLocation;
using Pap.Core.Utilities;
using Pap.Data;
using Pap.Data.Abstraction.Utils;
using Pap.Services;
using Pap.Services.WorkflowEngine;
using Pap.Web.Utils;
using Utils;

namespace Pap.Web.Modules.Loan.ViewModel
{
    /// <summary>
    /// 
    /// </summary>
    public class BoardMomViewModel : IViewModel
    {
        /// <summary>
        /// 
        /// </summary>
        ILoanRepository _LoanRepository;
        /// <summary>
        /// 
        /// </summary>
        IWorkflowService _WorkflowService;
        /// <summary>
        /// 
        /// </summary>
        IAdministrationRepository _AdministrationRepository;

        /// <summary>
        /// Initializes a new instance of the <see cref="BoardMomViewModel"/> class.
        /// </summary>
        /// <param name="loanRepository">The loan repository.</param>
        /// <param name="workflowService">The workflow service.</param>
        /// <param name="AdminRepository">The admin repository.</param>
        public BoardMomViewModel(ILoanRepository loanRepository, IWorkflowService workflowService, IAdministrationRepository AdminRepository)
        {
            _LoanRepository = loanRepository;
            _WorkflowService = workflowService;
            _AdministrationRepository = AdminRepository;
        }

        /// <summary>
        /// Gets the available actions.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ActionTypes> GetAvailableActions()
        {
            return _WorkflowService.GetAvailableActionsByStep(Steps.BoardList);
        }

        /// <summary>
        /// Gets the payment methods.
        /// </summary>
        /// <returns></returns>
        public IEnumerable<ILoanPaymentMethod> GetPaymentMethods()
        {
            return _LoanRepository.FindLoanPaymentMethods(pm => true);
        }

        /// <summary>
        /// Gets the new boards.
        /// </summary>
        /// <returns></returns>
        public IEnumerable GetNewBoards()
        {
            IEnumerable<IProject> userProjects = _AdministrationRepository.GetUserProjects(RegistryInfo.UserID);
            var allBoards = _LoanRepository.FindBoard(board => true);
            var boardMomBoardsIds = _WorkflowService.GetInStep(Steps.BoardMom);
            var notSubmittedBoardsIds = allBoards.Where(board => _WorkflowService.GetProcessInstanceByEntity(board.BoardID) == null).Select(board => board.BoardID);
            return (from board in allBoards
                    where (boardMomBoardsIds.Contains(board.BoardID) || notSubmittedBoardsIds.Contains(board.BoardID))
                    && (board.BoardLoans != null && userProjects.Contains(board.BoardLoans.First().LoanObj.ProjectStage.ProjectObj))
                    orderby board.BoardNumber ascending
                    let editable = notSubmittedBoardsIds.Contains(board.BoardID)
                    select new
                            {
                                BoardID = board.BoardID,
                                BoardNumber = board.BoardNumber,
                                BoardDate = board.BoardDate,
                                BoardStatus = editable ? "not submitted" : _WorkflowService.GetStep(_WorkflowService.GetProcessInstanceIDByEntity(board.BoardID)).ActionType.ToString(),
                                Editable = editable
                            });
        }

        /// <summary>
        /// Gets the board loans.
        /// </summary>
        /// <param name="BoardID">The board ID.</param>
        /// <returns></returns>
        public IEnumerable GetBoardLoans(Guid BoardID)
        {
            // var submittedBoardLoans = this._LoanRepository.FindCustomerLoans(loan => this._WorkflowService.GetInStep(Steps.BoardList).Contains(loan.LoanID));

            var result = (from boardLoan in _LoanRepository.FindBoardLoans(BL => BL.BoardID == BoardID)
                          //where (submittedBoardLoans.Select(bl => bl.LoanID).Contains(boardLoan.LoanID))
                          orderby boardLoan.LoanObj.LoanNumber ascending

                          let processInstID = _WorkflowService.GetProcessInstanceIDByEntity(boardLoan.LoanID)
                          let disabled = _WorkflowService.GetStep(processInstID).PreviousStepAction.ActionTypeID.Equals(
                          Enums.ToString(ActionTypes.RefusedFromBegining).ToGuid())

                          select new
                          {
                              LoanID = boardLoan.LoanID,
                              LoanNumber = boardLoan.LoanObj.LoanNumber,
                              LoanCreatedDate = boardLoan.LoanObj.LoanCreatedDate,
                              CustomerName = boardLoan.LoanObj.CustomerObj.CustomerName,
                              LoanType = boardLoan.LoanObj.LoanTypeObj.Name,
                              LoanAmount = boardLoan.LoanObj.LoanAmount,
                              FeasibleLoanAmount = boardLoan.LoanObj.FeasibilityStudyObj != null ? boardLoan.LoanObj.FeasibilityStudyObj.LoanAmount : 0.0,
                              FeasibleLoanPaymentPeriod = boardLoan.LoanObj.LoanPaymentPeriod,
                              BoardLoanAmount = boardLoan.BoardLoanAmount != null ? boardLoan.BoardLoanAmount.Value : (boardLoan.LoanObj.FeasibilityStudyObj != null ? boardLoan.LoanObj.FeasibilityStudyObj.LoanAmount : boardLoan.LoanObj.LoanAmount),
                              BoardPaymentPeriod = boardLoan.BoardPaymentPeriod != null ? boardLoan.BoardPaymentPeriod : (boardLoan.LoanObj.FeasibilityStudyObj != null ? boardLoan.LoanObj.FeasibilityStudyObj.LoanPaymentPeriod : boardLoan.LoanObj.LoanPaymentPeriod),
                              BoardpaymentMethodID = boardLoan.BoardPaymentMethodObj != null ? boardLoan.BoardPaymentMethodObj.LoanPaymentMethodID : (boardLoan.LoanObj.FeasibilityStudyObj != null ? boardLoan.LoanObj.FeasibilityStudyObj.LoanPaymentMethodID : boardLoan.LoanObj.LoanPaymentMethodID),
                              StatusNotes = boardLoan.StatusNotes != null ? boardLoan.StatusNotes : string.Empty,
                              PreviousNotes = _WorkflowService.GetStep(processInstID).PreviousNotes,
                              MinAmount = boardLoan.LoanObj.ProjectStage.From,
                              MaxAmount = boardLoan.LoanObj.ProjectStage.To,
                              Disabled = disabled,
                              DecisionID = disabled ? Enums.ToString(ActionTypes.Refuse) : string.Empty
                          });


            return result;

        }

        /// <summary>
        /// Gets the board by ID.
        /// </summary>
        /// <param name="boardID">The board ID.</param>
        /// <returns></returns>
        public IBoard GetBoardByID(Guid boardID)
        {
            return _LoanRepository.GetBoardByID(boardID);
        }

        // it never used
        /// <summary>
        /// Takes the loans decisions.
        /// </summary>
        /// <param name="LoanID">The loan ID.</param>
        /// <param name="action">The action.</param>
        /// <param name="Notes">The notes.</param>
        public void TakeLoansDecisions(Guid LoanID, Pap.Services.WorkflowEngine.ActionTypes action, string Notes)
        {
            Guid processInstanceID = _WorkflowService.GetProcessInstanceIDByEntity(LoanID);
            _WorkflowService.Move(action, processInstanceID, RegistryInfo.UserID, Notes, null);
        }

        /// <summary>
        /// Submits the board.
        /// </summary>
        /// <param name="BoardID">The board ID.</param>
        /// <param name="boardNotes">The board notes.</param>
        /// <param name="AttachmentsIDs">The attachments I ds.</param>
        /// <param name="deletedImages">The deleted images.</param>
        /// <param name="LoanDecisions">The loan decisions.</param>
        public void SubmitBoard(Guid BoardID, string boardNotes, IEnumerable<Guid> AttachmentsIDs, IEnumerable<Guid> deletedImages, Dictionary<Pap.Web.Modules.Loan.Views.BoardMom.BoardLoanData, Pap.Services.WorkflowEngine.ActionTypes> LoanDecisions)
        {
            using (IUnitOfWork trancaction = ServiceLocator.Current.GetInstance<IUnitOfWork>())
            {
                foreach (var item in LoanDecisions)
                {
                    Guid processInstanceID = _WorkflowService.GetProcessInstanceIDByEntity(item.Key.LoanID);
                    var step = _WorkflowService.GetStep(processInstanceID);
                    Guid decisionID = Enums.ToString(item.Value).ToGuid();
                    if (decisionID.Equals(Enums.ToString(ActionTypes.FreezWithoutResearchAndStudy).ToGuid()) ||
                        decisionID.Equals(Enums.ToString(ActionTypes.FreezWithResearchAndStudy).ToGuid()))
                        _WorkflowService.Move(item.Value, processInstanceID, RegistryInfo.UserID, item.Key.StatusNotes, step.CompletionDate);
                    else
                        _WorkflowService.Move(item.Value, processInstanceID, RegistryInfo.UserID, item.Key.StatusNotes, null);

                }

                foreach (var item in AttachmentsIDs)
                {
                    if (_LoanRepository.FindBoardAttachments(a => a.Attachment == item && a.BoardID == BoardID).Count() == 0)
                    {
                        IBoardAttachment boardAttachment = ServiceLocator.Current.GetInstance<IBoardAttachment>();
                        boardAttachment.BoardAttachmentID = Guid.NewGuid();
                        boardAttachment.BoardID = BoardID;
                        boardAttachment.Attachment = item;
                        _LoanRepository.CreateBoardAttachment(boardAttachment);
                    }
                }

                foreach (var imageID in deletedImages)
                {
                    IBoardAttachment att = _LoanRepository.FindBoardAttachments(a => a.Attachment == imageID).FirstOrDefault();
                    if (att != null)
                    {
                        _LoanRepository.DeleteBoardAttachment(att);
                    }
                }

                foreach (var item in LoanDecisions)
                {
                    var tempboardLoans = this._LoanRepository.FindBoardLoans(bl => bl.BoardID == BoardID && bl.LoanID == item.Key.LoanID);
                    if (tempboardLoans.Count() > 0)
                    {
                        IBoardLoan tempBoardLoan = tempboardLoans.First();
                        tempBoardLoan.BoardLoanAmount = item.Key.BoardLoanAmount;
                        tempBoardLoan.BoardpaymentMethodID = item.Key.BoardpaymentMethod;
                        tempBoardLoan.BoardPaymentPeriod = item.Key.BoardPaymentPeriod;
                        tempBoardLoan.StatusNotes = item.Key.StatusNotes;
                    }
                }

                //close the board
                IBoard board = _LoanRepository.GetBoardByID(BoardID);
                _WorkflowService.Move(ActionTypes.Submit, _WorkflowService.GetProcessInstanceIDByEntity(board.BoardID), RegistryInfo.UserID, boardNotes, null);

                trancaction.Commit();
            }
        }


        /// <summary>
        /// Saves the board.
        /// </summary>
        /// <param name="boardID">The board ID.</param>
        /// <param name="attachmentIDs">The attachment I ds.</param>
        /// <param name="deletedImages">The deleted images.</param>
        /// <param name="loanDecisions">The loan decisions.</param>
        public void SaveBoard(Guid boardID, IEnumerable<Guid> attachmentIDs, IEnumerable<Guid> deletedImages, Dictionary<Views.BoardMom.BoardLoanData, string> loanDecisions)
        {
            using (IUnitOfWork trancaction = ServiceLocator.Current.GetInstance<IUnitOfWork>())
            {
                foreach (var item in attachmentIDs)
                {
                    if (_LoanRepository.FindBoardAttachments(a => a.Attachment == item && a.BoardID == boardID).Count() == 0)
                    {
                        IBoardAttachment boardAttachment = ServiceLocator.Current.GetInstance<IBoardAttachment>();
                        boardAttachment.BoardAttachmentID = Guid.NewGuid();
                        boardAttachment.BoardID = boardID;
                        boardAttachment.Attachment = item;
                        _LoanRepository.CreateBoardAttachment(boardAttachment);
                    }
                }

                foreach (var imageID in deletedImages)
                {
                    IBoardAttachment att = _LoanRepository.FindBoardAttachments(a => a.Attachment == imageID).FirstOrDefault();
                    if (att != null)
                    {
                        _LoanRepository.DeleteBoardAttachment(att);
                    }
                }

                foreach (var item in loanDecisions)
                {
                    var tempboardLoans = this._LoanRepository.FindBoardLoans(bl => bl.BoardID == boardID && bl.LoanID == item.Key.LoanID);
                    if (tempboardLoans.Count() > 0)
                    {
                        IBoardLoan tempBoardLoan = tempboardLoans.First();
                        tempBoardLoan.BoardLoanAmount = item.Key.BoardLoanAmount;
                        tempBoardLoan.BoardpaymentMethodID = item.Key.BoardpaymentMethod;
                        tempBoardLoan.BoardPaymentPeriod = item.Key.BoardPaymentPeriod;
                        tempBoardLoan.StatusNotes = item.Key.StatusNotes;
                    }
                }

                trancaction.Commit();
            }
        }

        /// <summary>
        /// Gets the board attachements.
        /// </summary>
        /// <param name="boardID">The board ID.</param>
        /// <returns></returns>
        public IEnumerable<IImage> GetBoardAttachements(Guid boardID)
        {
            return _LoanRepository.GetBoardByID(boardID).BoardAttachments.Select(att => att.AttachmentImage);
        }

        /// <summary>
        /// Gets the board mom members.
        /// </summary>
        /// <param name="boardID">The board ID.</param>
        /// <returns></returns>
        public IEnumerable GetBoardMomMembers(Guid boardID)
        {
            return (from user in _LoanRepository.GetBoardByID(boardID).BoardMembers
                    select user).ToList();
        }

        /// <summary>
        /// Gets the loan by ID.
        /// </summary>
        /// <param name="loanID">The loan ID.</param>
        /// <returns></returns>
        public ICustomerLoan GetLoanByID(Guid loanID)
        {
            return _LoanRepository.GetCustomerLoanByID(loanID);
        }
    }
}
